#ifndef WAVE_H_
#define WAVE_H_


const double epsilon = 1e-12;

#define PI 3.14159265358979323846
#define D360 6.28318530717958647693
#define PI_180 0.01745329251994329577
#define HF_RES 128
#define MAX_PARTICLE_NUMBER 10000000
#define TIME_STEP 0.01f
#define PARTICLE_RADIUS 0.05f
#define WAVE_SPEED 0.5f
#define MAX_AMP 0.01f
#define MIN_AMP 0.00002f
#define CAUSTICS 0.2f

int windowWidth = 1024, windowHeight = 768;
double cameraNear = 0.1, cameraFar = 1000.0, cameraFovy = 45.0;
double cameraOR = 1.5, cameraOH = 300.0, cameraOV = 30.0;
int mouseOX, mouseOY;
double cameraR, cameraH, cameraV;
double cameraTR, cameraTH, cameraTV;
float genX, genY;
float eyePos[4];


int systemPaused = 0, cameraSetting = 0, generating = 0, renderParticles = 0, displayMode = 0, transparent = 0, testSwitch = 0;
float fading = 0.0f;
float time = 0.0f, h = TIME_STEP;
//Timer fps;

GLhandleARB xFilter, yFilter, gradient, water, caustics, bottom, cFilter;

GLuint poolBottom;
GLuint fb, fboTex[8], vb, nb, eb, cb;
GLenum colorAttachment[] = {
	GL_COLOR_ATTACHMENT0,
	GL_COLOR_ATTACHMENT1,
	GL_COLOR_ATTACHMENT2,
	GL_COLOR_ATTACHMENT3,
	GL_COLOR_ATTACHMENT4,
	GL_COLOR_ATTACHMENT5,
	GL_COLOR_ATTACHMENT6,
	GL_COLOR_ATTACHMENT7};

GLuint indices[(HF_RES - 1) * (HF_RES - 1) * 6];
GLuint maxIndex = (HF_RES - 1) * (HF_RES - 1) * 6;

GLfloat lightPos[] = {-0.8f, 0.2f, 1.2f, 1.0f};




struct WaveParticle {
	float x, y, a;
	float amp, da, bt, st, tx, ty;
	double vx, vy;
	int rx, ry;
};

WaveParticle wp[MAX_PARTICLE_NUMBER];
int wpNum;

static void initializeGL(void)
{
	GLenum err = glewInit();

	if(err != GLEW_OK)
		fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
	else {
		printf("Vendor:   %s\n", glGetString(GL_VENDOR));
		printf("Renderer: %s\n", glGetString(GL_RENDERER));
		printf("Version:  %s\n", glGetString(GL_VERSION));
	}
	printf("--------------------------------------------------\n");

	if (glewIsSupported("GL_VERSION_2_1"))
		printf("OpenGL 2.1                      supported\n");
	else
		printf("OpenGL 2.1                      NOT supported\n");
	if (glewIsSupported("GL_ARB_vertex_buffer_object"))
		printf("GL_ARB_vertex_buffer_object     supported\n");
	else
		printf("GL_ARB_vertex_buffer_object     NOT supported\n");
	if (glewIsSupported("GL_ARB_half_float_pixel"))
		printf("GL_ARB_half_float_pixel         supported\n");
	else
		printf("GL_ARB_half_float_pixel         NOT supported\n");
	if (glewIsSupported("GL_ARB_half_float_pixel"))
		printf("GL_EXT_framebuffer_multisample  supported\n");
	else
		printf("GL_EXT_framebuffer_multisample  NOT supported\n");
	printf("--------------------------------------------------\n");

	GLint number;
	glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB, &number);
	printf("GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB = %d\n", number);
	glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB, &number);
	printf("GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB = %d\n", number);
	glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &number);
	printf("GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS   = %d\n", number);
	glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &number);
	printf("GL_MAX_COLOR_ATTACHMENTS       = %d\n", number); 
	printf("--------------------------------------------------\n");


	cameraR = cameraOR; cameraH = cameraOH; cameraV = cameraOV;
	eyePos[0] = cameraR * cos(cameraH * PI_180) * cos(cameraV * PI_180) + 0.5f;
	eyePos[1] = cameraR * sin(cameraH * PI_180) * cos(cameraV * PI_180) + 0.5f;
	eyePos[2] = cameraR * sin(cameraV * PI_180);
	eyePos[3] = 1.0f;

	glEnable(GL_DEPTH_TEST);
}

static bool loadShader(GLhandleARB shader, const char* filename)
{
	FILE *fp;
	GLubyte *buf;
	int len;

	//fopen_s(&fp, filename, "rb");  
	fp = fopen(filename, "rb");  // MODIFIED
	fseek(fp, 0, SEEK_END);
	len = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	buf = new GLubyte[len + 1];
	fread(buf, 1, len, fp);
	buf[len] = '\0';
	glShaderSourceARB(shader, 1, (const char**)&buf, &len);
	if (glGetError() != 0) return false;
	fclose(fp);
	delete []buf;

	return true;
}

static void printInfoLog(GLhandleARB obj)
{
	int infoLogLength = 0, charsWritten = 0;
	GLcharARB* infoLog;

	glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infoLogLength);
	if (infoLogLength > 0) {
		infoLog = (GLcharARB*)malloc(infoLogLength);
		if (infoLog == NULL) {
			printf("ERROR: Could not allocate InfoLog buffer\n");
			exit(1);
		}
		glGetInfoLogARB(obj, infoLogLength, &charsWritten, infoLog);
		printf("%s\n", infoLog);
		delete []infoLog;
	}
}

static GLhandleARB createProgram(const char *name, const char *vname, const char *fname)
{
	GLhandleARB programHandle, vertexShader, fragmentShader;

	printf("%s\n", name);
	programHandle = glCreateProgramObjectARB();
	vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
	fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
	loadShader(vertexShader, vname);
	loadShader(fragmentShader, fname);
	glCompileShaderARB(vertexShader);
	printInfoLog(vertexShader);
	glCompileShaderARB(fragmentShader);
	printInfoLog(fragmentShader);
	glAttachObjectARB(programHandle, vertexShader);
	glAttachObjectARB(programHandle, fragmentShader);
	glLinkProgramARB(programHandle);
	printInfoLog(programHandle);
	printf("--------------------------------------------------\n");

	return programHandle;
}

static void reshape(int width, int height)
{
	glViewport(0, 0, width, height);
	windowWidth = width; windowHeight = height;
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(cameraFovy, (GLdouble)windowWidth / (GLdouble)windowHeight, cameraNear, cameraFar);
	glMatrixMode(GL_MODELVIEW);
}


static void xTest(int i)
{
	float t = wp[i].st - wp[i].bt;
	float x = wp[i].x + t * wp[i].vx;
	if (x < 0.0f) {
		wp[i].tx = wp[i].bt - t / (x - wp[i].x) * wp[i].x;
		wp[i].rx = 1;
	}
	else if (x > 1.0f) {
		wp[i].tx = wp[i].bt + t / (x - wp[i].x) * (1.0f - wp[i].x);
		wp[i].rx = 2;
	}
	else
		wp[i].rx = 0;
}

static void yTest(int i)
{
	float t = wp[i].st - wp[i].bt;
	float y = wp[i].y + t * wp[i].vy;
	if (y < 0.0f) {
		wp[i].ty = wp[i].bt - t / (y - wp[i].y) * wp[i].y;
		wp[i].ry = 1;
	}
	else if (y > 1.0f) {
		wp[i].ty = wp[i].bt + t / (y - wp[i].y) * (1.0f - wp[i].y);
		wp[i].ry = 2;
	}
	else
		wp[i].ry = 0;
}


void generateNewParticle(float x, float y, float amp)
{
	int i, j, count;
	int n = 9;
	float d = 0.25f * PARTICLE_RADIUS / sin(4.5f * PI / n);
	float angle = D360 / n;
	float c = 0.25f * PARTICLE_RADIUS / WAVE_SPEED;

	count = 0;
	for (i = 0; i < n; i++) {
		j = wpNum + count;
		wp[j].da = angle / 1.5f;
		wp[j].a = angle * i;
		wp[j].x = x + d * cos(wp[j].a);
		wp[j].y = y + d * sin(wp[j].a);
		if (wp[j].x > 0.0f && wp[j].x < 1.0f && wp[j].y > 0.0f && wp[j].y < 1.0f)
			count++;
		else
			continue;
		wp[j].vx = WAVE_SPEED * cos(wp[j].a);
		wp[j].vy = WAVE_SPEED * sin(wp[j].a);
		wp[j].amp = amp;
		wp[j].bt = time - 0.05f;
		wp[j].st = wp[j].bt + c / sin(wp[j].da);
		xTest(j); yTest(j);
	}
	wpNum += count;
	//systemPaused = 1;
}

void iteration(void)
{
	int i, j, k, tempNum;
	float c, t;
	float old_x, old_y, old_a, old_da, old_vx, old_vy;
	float new_da, new_amp, new_bt, new_st;

	time += h;
/*
	i = 0;
	printf ("hello \n.");

	while (i < wpNum) {
		if (wp[i].st < time && wp[i].amp < MIN_AMP * 3.0f) {
			wpNum--;
			if (i < wpNum) {
				wp[i].x = wp[wpNum].x; wp[i].y = wp[wpNum].y;
				wp[i].a = wp[wpNum].a; wp[i].da = wp[wpNum].da;
				wp[i].vx = wp[wpNum].vx; wp[i].vy = wp[wpNum].vy;
				wp[i].amp = wp[wpNum].amp;
				wp[i].bt = wp[wpNum].bt; wp[i].st = wp[wpNum].st;
				wp[i].tx = wp[wpNum].tx; wp[i].ty = wp[wpNum].ty;
				wp[i].rx = wp[wpNum].rx; wp[i].ry = wp[wpNum].ry;
			}
		}
		else
			i++;
	}
	*/

	c = 0.25f * PARTICLE_RADIUS / WAVE_SPEED;
	tempNum = wpNum;
	for (i = 0; i < tempNum; i++) {
		if (wp[i].rx == 1 && wp[i].tx < time) {
			wp[i].x = -wp[i].x;
			wp[i].a = PI - wp[i].a;
			wp[i].vx = -wp[i].vx;
			wp[i].rx = 0;
			xTest(i);
		}
		else if (wp[i].rx == 2 && wp[i].tx < time) {
			wp[i].x = 2.0f - wp[i].x;
			wp[i].a = PI - wp[i].a;
			wp[i].vx = -wp[i].vx;
			wp[i].rx = 0;
			xTest(i);
		}
		if (wp[i].ry == 1 && wp[i].ty < time) {
			wp[i].y = -wp[i].y;
			wp[i].a = -wp[i].a;
			wp[i].vy = -wp[i].vy;
			wp[i].ry = 0;
			yTest(i);
		}
		else if (wp[i].ry == 2 && wp[i].ty < time) {
			wp[i].y = 2.0f - wp[i].y;
			wp[i].a = -wp[i].a;
			wp[i].vy = -wp[i].vy;
			wp[i].ry = 0;
			yTest(i);
		}
		if (wp[i].st < time) {
			t = wp[i].st - wp[i].bt;
			old_x = wp[i].x;
			old_y = wp[i].y;
			old_vx = wp[i].vx;
			old_vy = wp[i].vy;
			old_a = wp[i].a;
			old_da = wp[i].da;
			new_da = old_da / 3.0f; //
			new_amp = wp[i].amp / 3.0f;
			new_bt = wp[i].st;
			new_st = new_bt + c / sin(new_da);

			for (j = 0; j < 3; j++) {
				if (j == 0) {
					k = wpNum;
					wp[k].a = old_a - old_da * 0.5f;
					wp[k].x = old_x + WAVE_SPEED * cos(old_a - old_da / 1.5f) * t;
					wp[k].y = old_y + WAVE_SPEED * sin(old_a - old_da / 1.5f) * t;
				}
				else if (j == 1) {
					k = i;
					wp[k].a = old_a;
					wp[k].x = old_x + old_vx * t;
					wp[k].y = old_y + old_vy * t;
				}
				else {
					k = wpNum + 1;
					wp[k].a = old_a + old_da * 0.5f;
					wp[k].x = old_x + WAVE_SPEED * cos(old_a + old_da / 1.5f) * t;
					wp[k].y = old_y + WAVE_SPEED * sin(old_a + old_da / 1.5f) * t;
				}
				wp[k].vx = WAVE_SPEED * cos(wp[k].a);
				wp[k].vy = WAVE_SPEED * sin(wp[k].a);
				wp[k].da = new_da;
				wp[k].amp = new_amp;
				wp[k].bt = new_bt;
				wp[k].st = new_st;
				xTest(k); yTest(k);
			}
			wpNum += 2;
			//systemPaused = 1;
		}
	}
}

void renderText(void)
{
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(0, windowWidth, windowHeight, 0);
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
	glDisable(GL_DEPTH_TEST);
	glColor3f(1.0f, 1.0f, 1.0f);

	char buffer[256];

//	sprintf_s(buffer, 256, "FPS: %.1f", fps.avgHz());
	glRasterPos2f(5.0f, 20.0f);
	for (char* s = buffer; *s != '\0'; s++)
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *s);

	sprintf(buffer,  "Number of Wave Particles: %d", wpNum);
	glRasterPos2f(5.0f, 40.0f);
	for (char* s = buffer; *s != '\0'; s++)
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *s);

	glEnable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();
}

void renderWaveParticles(void)
{
	int i;
	float t;

	glViewport(windowWidth - 256, windowHeight - 256, 256, 256);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(0.0, 1.0, 0.0, 1.0);
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
	glDisable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glColor4f(0.2f, 0.2f, 0.2f, fading);
	glBegin(GL_QUADS);
	glVertex2f(0.0f, 0.0f);
	glVertex2f(1.0f, 0.0f);
	glVertex2f(1.0f, 1.0f);
	glVertex2f(0.0f, 1.0f);
	glEnd();

	glColor4f(1.0f, 1.0f, 1.0f, fading);
	glBegin(GL_POINTS);
	
	for (i = 0; i < wpNum; i++) {
		t = time - wp[i].bt;
		glVertex2f(wp[i].x + wp[i].vx * t, wp[i].y + wp[i].vy * t);
		//glVertex2f(wp[i].x, wp[i].y );
	}
	
	glEnd();

	char buffer[256];

	glColor4f(1.0f, 0.0f, 0.0f, fading);
	sprintf(buffer,  "Wave Particles");
	glRasterPos2f(0.28f, 0.93f);
	for (char* s = buffer; *s != '\0'; s++)
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *s);

	if (renderParticles && fading < 1.0f) fading += 0.02f;
	else fading -= 0.02f;

	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();
	glViewport(0, 0, windowWidth, windowHeight);
}


void initializeGPU()
{
	xFilter = createProgram("xFilter", "../Shaders/xFilter.vert", "../Shaders/xFilter.frag");
	yFilter = createProgram("yFilter", "../Shaders/yFilter.vert", "../Shaders/yFilter.frag");
	gradient = createProgram("gradient", "../Shaders/gradient.vert", "../Shaders/gradient.frag");
	water = createProgram("water", "../Shaders/water.vert", "../Shaders/water.frag");
	bottom = createProgram("bottom", "../Shaders/bottom.vert", "../Shaders/bottom.frag");
	caustics = createProgram("caustics", "../Shaders/caustics.vert", "../Shaders/caustics.frag");
	cFilter = createProgram("cFilter", "../Shaders/cFilter.vert", "../Shaders/cFilter.frag");

	glUseProgramObjectARB(xFilter);
//	glUniform1iARB(glGetUniformLocationARB(xFilter, "tex"), 0);
	glUniform1iARB(glGetUniformLocationARB(xFilter, "size"), HF_RES);
	glUniform1fARB(glGetUniformLocationARB(xFilter, "pr"), PARTICLE_RADIUS);
	glUseProgramObjectARB(0);	

	glUseProgramObjectARB(yFilter);
//	glUniform1iARB(glGetUniformLocationARB(yFilter, "tex"), 0);
	glUniform1iARB(glGetUniformLocationARB(yFilter, "size"), HF_RES);
	glUniform1fARB(glGetUniformLocationARB(yFilter, "pr"), PARTICLE_RADIUS);
	glUseProgramObjectARB(0);

	glUseProgramObjectARB(gradient);
//	glUniform1iARB(glGetUniformLocationARB(gradient, "tex"), 0);
	glUniform1iARB(glGetUniformLocationARB(gradient, "size"), HF_RES);
	glUseProgramObjectARB(0);

	glUseProgramObjectARB(water);
	glUniform4fARB(glGetUniformLocationARB(water, "lightPosition"), lightPos[0], lightPos[1], lightPos[2], lightPos[3]);
	glUniform1iARB(glGetUniformLocationARB(water, "bottomTex"), 0);
	glUniform1iARB(glGetUniformLocationARB(water, "causticsTex"), 1);
	glUseProgramObjectARB(0);

	glUseProgramObjectARB(bottom);
	glUniform1iARB(glGetUniformLocationARB(bottom, "bottomTex"), 0);
	glUniform1iARB(glGetUniformLocationARB(bottom, "causticsTex"), 1);
	glUseProgramObjectARB(0);

	glUseProgramObjectARB(caustics);
	glUniform4fARB(glGetUniformLocationARB(caustics, "lightPosition"), lightPos[0], lightPos[1], lightPos[2], lightPos[3]);
	glUniform1iARB(glGetUniformLocationARB(caustics, "hftex"), 0);
	glUniform1iARB(glGetUniformLocationARB(caustics, "ntex"), 1);
	glUniform1iARB(glGetUniformLocationARB(caustics, "size"), HF_RES);
	glUseProgramObjectARB(0);

	glUseProgramObjectARB(cFilter);
	glUniform1iARB(glGetUniformLocationARB(cFilter, "causticsTex"), 0);
	glUniform1iARB(glGetUniformLocationARB(cFilter, "size"), HF_RES);
	glUniform1fARB(glGetUniformLocationARB(cFilter, "causticsIntensity"), CAUSTICS);
	glUseProgramObjectARB(0);

	int x, y, n = 0;
	for (y = 0; y < HF_RES - 1; y++) {
		for (x = 0; x < HF_RES - 1; x++) {
			indices[n] = y * HF_RES + x;
			indices[n + 1] = indices[n] + 1;
			indices[n + 2] = indices[n + 1] + HF_RES;
			indices[n + 3] = indices[n];
			indices[n + 4] = indices[n + 2];
			indices[n + 5] = indices[n + 4] - 1;
			n += 6;
		}
	}

#define DATA_INTERNAL GL_RGBA32F
#define DATA_FORMAT GL_RGBA
#define DATA_TYPE GL_FLOAT
#define TYPE_SIZE 4

	glGenBuffersARB(1, &vb);
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, vb);
	glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, HF_RES * HF_RES * 4 * TYPE_SIZE, 0, GL_STREAM_DRAW_ARB);

	glGenBuffersARB(1, &nb);
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, nb);
	glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, HF_RES * HF_RES * 4 * TYPE_SIZE, 0, GL_STREAM_DRAW_ARB);

	glGenBuffersARB(1, &eb);
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, eb);
	glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, maxIndex * sizeof(GLuint), indices, GL_STATIC_DRAW_ARB);

	glGenBuffersARB(1, &cb);
	glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, cb);
	glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, HF_RES * HF_RES * 4 * TYPE_SIZE, 0, GL_STREAM_DRAW_ARB);

	glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0);

	glGenTextures(8, fboTex);
	glGenFramebuffersEXT(1, &fb); 
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
	for (int i = 0; i < 8; i++) {
		glBindTexture(GL_TEXTURE_2D, fboTex[i]); 
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
		glTexImage2D(GL_TEXTURE_2D, 0, DATA_INTERNAL, HF_RES, HF_RES, 0, DATA_FORMAT, DATA_TYPE, 0);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, colorAttachment[i], GL_TEXTURE_2D, fboTex[i], 0);
	}
	glBindTexture(GL_TEXTURE_2D, fboTex[6]); 
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		
	Bitmap b;
	b.Load("../Textures/bottom.bmp");

	glGenTextures(1, &poolBottom);
	glBindTexture(GL_TEXTURE_2D, poolBottom);
   	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
   	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
   	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, b.GetWidth(), b.GetHeight(), 0, GL_RGB, GL_FLOAT, b.toFloat());
}


#endif
